fix(cloudflare): resolve D1 databases by name without total_pages - #3095
dchaudhari7177 wants to merge 2 commits into
Conversation
databaseByName required result_info.total_pages, which the D1 list endpoint never returns, so every --d1 <name> lookup failed with "total_pages is invalid". Derive the page count from total_count and per_page when the field is absent. The test stub synthesized total_pages, which is why CI passed; add cases using the live envelope. The endpoint's name parameter is a substring filter, and every row was validated as a production deployment target before the exact-name filter, so a preview database named site-db-staging failed the lookup for site-db. Filter by exact name first. Closes emdash-cms#2840
🦋 Changeset detectedLatest commit: 4839bac The changes in this PR will be included in the next version bump. This PR includes changesets to release 18 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
This PR fixes a real, well-scoped bug: emdash migrate --d1 <name> failed because the Cloudflare D1 list endpoint does not return total_pages, so the strict validator rejected every name lookup before any row was inspected. The fix derives the page count from total_count / per_page when total_pages is absent, and the secondary improvement filters rows by exact name before calling the deployment-target validator, preventing substring-match preview databases from aborting an otherwise valid lookup.
The approach is correct and narrowly targeted: only databaseByName changes, the --d1 <uuid> and --wrangler-config paths are untouched, and the existing envelope shape (with total_pages) continues to be accepted and validated exactly as before. I checked the new listResultInfo logic, the pagination validation guard (totalPages === 0 special case, MAX_DATABASE_LIST_PAGES, seenCount === totalCount), and the filter-before-validate ordering. The boundary cases I traced (empty result, single page, multi-page walk, exact-name match, exact-name preview match, substring preview/development match) all behave correctly.
The added test cases exercise the live envelope without total_pages, including multi-page derivation and the preview-substring case, and the existing tests continue to cover the legacy envelope. The changeset names the affected command and pins the exact error message a user would see, which meets the .changeset/README.md standard. No AGENTS.md conventions are violated: no content-table queries, no auth/UI/locale changes, no new logged-out hot-path queries, and the added comments explain the non-obvious API behavior / validation ordering without referencing PRs or issue numbers.
Clean fix with good coverage — LGTM.
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-test
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/registry-moderation
@emdash-cms/registry-verification
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
What does this PR do?
emdash migrate --d1 <name>could never resolve a name.databaseByNamevalidated pagination withlistInteger(value.total_pages, …), but the D1 list endpoint'sresult_infois{ count, page, per_page, total_count }with nototal_pages, so every lookup threwCloudflare D1 database list total_pages is invalid.before looking at a single row. UUIDs and--wrangler-configwere unaffected.total_pagesis absent, it is derived asceil(total_count / per_page). When present it is validated as before. Everything downstream (the page loop, the cross-page consistency check,MAX_DATABASE_LIST_PAGES, the finalseenCount === totalCountcheck) is unchanged and now runs on a value the endpoint actually implies.nameis a substring filter, and every row went throughmetadataDatabasebefore the exact-name filter. That throws for any non-production row, so once paging worked, a previewsite-db-stagingon the same page would still have failed the lookup forsite-db. Rows are now filtered by exact name first, and only the matches are validated as deployment targets.Closes #2840
Type of change
Checklist
pnpm typecheckpasses:tsc --noEmit -p packages/cloudflarereports the same 7 errors on this branch and onmain(unbuiltemdashworkspace types), none in the touched filepnpm lintpasses:oxlint --deny-warningson the touched filespnpm testpasses (or targeted tests for my change): see belowpnpm formathas been run:oxfmtAI-generated code disclosure
Screenshots / test output
Not applicable (CLI). The test stub
listApiResponsesynthesizedtotal_pages, which is why CI never saw this. The new cases inpackages/cloudflare/tests/db/d1-migration-target.test.tsuse aliveListApiResponseshaped like the endpoint the issue recorded:total_count: 2, per_page: 1;site-db-staginglisted next tosite-db;No D1 database named site-dbfor an empty result.The one failure on both trees is
uses the selected Wrangler environment and its own binding array, which asserts/project/wrangler.jsoncand gets a Windows path separator on this machine. CI on Linux should pass it. I did not run this against the live Cloudflare API.